﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Drawing;
using System.Security.Cryptography;
namespace Utilities
{
    public class Common
    {
        #region Http
        public static HttpContext Current
        {
            get { return HttpContext.Current; }
        }

        public static HttpRequest Request
        {
            get { return Current.Request; }
        }

        public static HttpResponse Response
        {
            get { return Current.Response; }
        }
        #endregion

        #region 加密

        #region 散列加密
        /// <summary>
        /// MD5加密 
        /// </summary>
        /// <param name="sValue">需要加密的字符串</param>
        /// <returns>加密过的字符串</returns>
        public static string GetMD5(string sValue)
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            return BitConverter.ToString(md5.ComputeHash(Encoding.Default.GetBytes(sValue)), 4, 8).Replace("-", "").ToLower();
        }
        /// <summary>
        /// SHA-384散列加密（已加盐值）
        /// </summary>
        /// <param name="sValue">需要加密的字符串</param>
        /// <returns>加密过的字符串</returns>
        public static string GetSha384(string sValue)
        {
            sValue += "8,$n";
            System.Security.Cryptography.SHA384 s384 = new System.Security.Cryptography.SHA384Managed();
            byte[] byte1;
            byte1 = s384.ComputeHash(Encoding.GetEncoding("utf-8").GetBytes(sValue));
            s384.Clear();
            return Encoding.GetEncoding("utf-8").GetString(byte1);
        }
        #endregion

        #region AES对称加密
        /// <summary>  
        /// 创建Rijndael SymmetricAlgorithm   
        /// </summary>     
        /// <param name="password">密码</param>  
        /// <returns>加密对象</returns>      
        private static SymmetricAlgorithm CreateRijndael(string password)
        {
            //创建密码
            //参数1密码，2盐值，3算法名，4迭代的次数
            //密码还可以sma.GenerateKey生成存储起来用
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, Encoding.UTF8.GetBytes("#@dX<"), "SHA256", 56);
            //执行那个算法
            SymmetricAlgorithm sma = Rijndael.Create();
            sma.GenerateIV();//生成向量
            sma.KeySize = 256;
            sma.Key = pdb.GetBytes(32);//256/8=32一个字节8位二进制
            return sma;
        }


        /// <summary>
        /// 加密字符串
        /// </summary>
        /// <param name="plainText">需要加密的字符串</param>
        /// <param name="passWord">密码</param>
        /// <returns>加密后的字符串</returns>
        public static string EncryptString(string plainText, string passWord)
        {
            //将字符串转换为字节数组
            byte[] clearData = Encoding.UTF8.GetBytes(plainText);
            SymmetricAlgorithm algorithm = CreateRijndael(passWord);//创建
            MemoryStream ms = new MemoryStream();//新建一个流
            ms.Write(algorithm.IV, 0, algorithm.IV.Length);
            CryptoStream cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(clearData, 0, clearData.Length);
            cs.FlushFinalBlock();
            string rtstring = Convert.ToBase64String(ms.ToArray());
            cs.Close();
            ms.Close();
            return rtstring;
        }


        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="decryptTest">需要解密的字符串</param>
        /// <param name="passWord">密码</param>
        /// <returns>解密后的字符串</returns>
        public static string DecryptString(string decryptTest, string passWord)
        {
            SymmetricAlgorithm algorithm = CreateRijndael(passWord);
            byte[] data = Convert.FromBase64String(decryptTest);
            MemoryStream ms = new MemoryStream();
            int ReadPos = 0;
            byte[] IV = new byte[algorithm.IV.Length];
            Array.Copy(data, IV, IV.Length);
            algorithm.IV = IV;
            ReadPos += algorithm.IV.Length;
            CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);
            cs.Write(data, ReadPos, data.Length - ReadPos);
            cs.FlushFinalBlock();
            string rtstring = Encoding.UTF8.GetString(ms.ToArray());
            cs.Close();
            ms.Close();
            return rtstring;
        }
        #endregion

        #endregion

        #region 上传文件
        /// <summary>
        /// 上传文件（返回文件相对路径或错误方式）
        /// </summary>
        /// <param name="file">需要上传的文件</param>
        /// <param name="type">类型：img为图片，""不限。等需要可扩展</param>
        /// <param name="maxSize">上传文件最大占用空间单位KB</param>
        /// <param name="mapPath">保存路径（虚拟路径例“/Upload/Images/”）</param>
        /// <param name="nameType">保存文件名字方式:1为按月，2为按天</param>
        /// <param name="i">传出参数是否成功</param>
        /// <returns>文件相对路径或错误方式</returns>
        public static string UpLoad(HttpPostedFileBase file, string type, int maxSize, string mapPath, int nameType, ref bool i)
        {
            i = true;
            if (file.ContentLength < maxSize * 1024)
            {
                //string fileContentType = file.ContentType;//文件格式。
                string dtime;//创建文件夹用，按参数方式创建文件夹，用于保存文件。
                string fileName;//创建文件用，按参数方式常见文件名字。
                string fileType = Path.GetExtension(file.FileName);//文件类型后缀扩展名。
                switch (nameType)
                {
                    case 1:
                        dtime = string.Format("{0:yyMM}", DateTime.Now);
                        fileName = string.Format("{0:ddHHssff}{1}", DateTime.Now, fileType);
                        break;
                    case 2:
                        dtime = string.Format("{0:yyMMdd}", DateTime.Now);
                        fileName = string.Format("{0:HHssff}{1}", DateTime.Now, fileType);
                        break;
                    default:
                        dtime = string.Format("{0:yyMM}", DateTime.Now);
                        fileName = string.Format("{0:ddHHssff}{1}", DateTime.Now, fileType);
                        break;
                }
                string treePath = Current.Server.MapPath(mapPath + dtime); //保存文件的路径
                string filePath = treePath + "/" + fileName;//文件绝对路径
                string filePath1 = mapPath + dtime + "/" + fileName;//文件相对路径，用于存入数据库及返回给页面展示。                            
                switch (type)
                {
                    case "img":
                        if (fileType == ".gif" || fileType == ".jpeg" || fileType == ".png" || fileType == ".jpg")
                        {

                            if (!Directory.Exists(treePath)) //如果保存图片的目录不存在，由创建它  
                            {
                                System.IO.Directory.CreateDirectory(treePath);
                            }
                            file.SaveAs(filePath);
                            return filePath1;
                        }
                        else
                        {
                            i = false;
                            return "格式不正确，非图片格式";
                        }
                    default:
                        if (!Directory.Exists(treePath)) //如果保存图片的目录不存在，由创建它  
                        {
                            System.IO.Directory.CreateDirectory(treePath);
                        }
                        file.SaveAs(filePath);
                        return filePath1;
                }
            }
            else
            {
                i = false;
                return string.Format("上传文件大小不能大于{0}Kb", maxSize);
            }
        }
        #endregion
    }

    #region 验证码类
    /// <summary>
    /// 验证码类
    /// </summary>
    public class VerifyCode
    {
        #region 验证码长度(默认4个验证码的长度)
        /// <summary>
        /// 验证码长度
        /// </summary>
        public int Length { get; set; }
        #endregion

        #region 验证码字体大小(为了显示扭曲效果，默认40像素，可以自行修改)
        /// <summary>
        /// 验证码字体大小
        /// </summary>
        public int FontSize { get; set; }
        #endregion

        #region 是否输出燥点(默认输出)
        /// <summary>
        /// 是否输出燥点
        /// </summary>
        public bool Chaos { get; set; }
        #endregion

        #region 自定义背景色(默认白色)
        /// <summary>
        /// 背景色
        /// </summary>
        public Color BackgroundColor { get; set; }
        #endregion

        #region 输出燥点的颜色(默认灰色)
        /// <summary>
        /// 输出燥点的颜色
        /// </summary>
        public Color ChaosColor { get; set; }
        #endregion

        #region 自定义随机颜色数组
        /// <summary>
        /// 自定义随机颜色数组
        /// </summary>
        public Color[] Colors { get; set; }
        #endregion

        #region 自定义字体数组
        /// <summary>
        /// 自定义字体数组
        /// </summary>
        public string[] Fonts { get; set; }
        #endregion

        #region 自定义随机码字符串序列(使用逗号分隔)
        /// <summary>
        /// 自定义随机码字符串序列
        /// </summary>
        public string CodeSerial { get; set; }
        #endregion

        #region 边框补(默认1像素)
        /// <summary>
        /// 边框补
        /// </summary>
        public int Padding { get; set; }
        #endregion

        #region 验证码
        /// <summary>
        /// 验证码
        /// </summary>
        public string Code { get; set; }
        #endregion

        public VerifyCode()
        {
            Length = 4;
            FontSize = 10;
            Chaos = true;
            BackgroundColor = Color.White;
            ChaosColor = Color.LightGray;
            Colors = new Color[] { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };
            Fonts = new string[] { "Arial", "Georgia" };
            CodeSerial = "0,1,2,3,4,5,6,7,8,9";
            Padding = 1;
            Code = CreateVerifyCode();
        }

        #region 将创建好的图片输出到页面
        /// <summary>
        /// 将创建好的图片输出到页面
        /// </summary>
        /// <param name="code">要生成的字符</param>
        /// <param name="context"></param>
        public byte[] CreateImageOnPage()
        {

            MemoryStream ms = new MemoryStream();
            Bitmap image = this.CreateImageCode(Code);
            try
            {
                image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

                return ms.ToArray();
            }
            finally
            {
                ms.Close();
                ms = null;
                image.Dispose();
                image = null;
            }
        }
        #endregion

        #region 生成随机字符码
        /// <summary>
        /// 生成随机字符码
        /// </summary>
        /// <returns></returns>
        public string CreateVerifyCode()
        {
            string[] arr = CodeSerial.Split(',');

            string code = "";

            int randValue = -1;

            Random rand = new Random(unchecked((int)DateTime.Now.Ticks));

            for (int i = 0; i < Length; i++)
            {
                randValue = rand.Next(0, arr.Length - 1);

                code += arr[randValue];
            }

            return code;
        }
        #endregion

        #region 生成校验码图片
        /// <summary>
        /// 生成效验码图片
        /// </summary>
        /// <param name="code">要生成的字符</param>
        /// <returns></returns>
        public Bitmap CreateImageCode(string code)
        {
            int fSize = FontSize;
            int fWidth = fSize + Padding;

            int imageWidth = (int)(code.Length * fWidth) + 4 + Padding * 2;
            int imageHeight = fSize * 2 + Padding;

            System.Drawing.Bitmap image = new System.Drawing.Bitmap(imageWidth, imageHeight);

            Graphics g = Graphics.FromImage(image);

            g.Clear(BackgroundColor);

            Random rand = new Random();

            //给背景添加随机生成的燥点
            if (this.Chaos)
            {

                Pen pen = new Pen(ChaosColor, 0);
                int c = Length * 10;

                for (int i = 0; i < c; i++)
                {
                    int x = rand.Next(image.Width);
                    int y = rand.Next(image.Height);

                    g.DrawRectangle(pen, x, y, 1, 1);
                }
            }

            int left = 0, top = 0, top1 = 1, top2 = 1;

            int n1 = (imageHeight - FontSize - Padding * 2);
            int n2 = n1 / 4;
            top1 = n2;
            top2 = n2 * 2;

            Font f;
            Brush b;

            int cindex, findex;

            //随机字体和颜色的验证码字符
            for (int i = 0; i < code.Length; i++)
            {
                cindex = rand.Next(Colors.Length - 1);
                findex = rand.Next(Fonts.Length - 1);

                f = new System.Drawing.Font(Fonts[findex], fSize, System.Drawing.FontStyle.Bold);
                b = new System.Drawing.SolidBrush(Colors[cindex]);

                if (i % 2 == 1)
                {
                    top = top2;
                }
                else
                {
                    top = top1;
                }

                left = i * fWidth;

                g.DrawString(code.Substring(i, 1), f, b, left, top);
            }

            //画一个边框 边框颜色为Color.Gainsboro
            g.DrawRectangle(new Pen(Color.Gainsboro, 0), 0, 0, image.Width - 1, image.Height - 1);
            g.Dispose();

            //产生波形
            //image = TwistImage(image, true, 8, 4);

            return image;
        }
        #endregion

        #region 产生波形滤镜效果

        private const double PI = 3.1415926535897932384626433832795;
        private const double PI2 = 6.283185307179586476925286766559;

        /// <summary>
        /// 正弦曲线Wave扭曲图片（Edit By 51aspx.com）
        /// </summary>
        /// <param name="srcBmp">图片路径</param>
        /// <param name="bXDir">如果扭曲则选择为True</param>
        /// <param name="nMultValue">波形的幅度倍数，越大扭曲的程度越高，一般为3</param>
        /// <param name="dPhase">波形的起始相位，取值区间[0-2*PI)</param>
        /// <returns></returns>
        public System.Drawing.Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
        {
            System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);

            // 将位图背景填充为白色
            System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
            graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destBmp.Width, destBmp.Height);
            graph.Dispose();

            double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;

            for (int i = 0; i < destBmp.Width; i++)
            {
                for (int j = 0; j < destBmp.Height; j++)
                {
                    double dx = 0;
                    dx = bXDir ? (PI2 * (double)j) / dBaseAxisLen : (PI2 * (double)i) / dBaseAxisLen;
                    dx += dPhase;
                    double dy = Math.Sin(dx);

                    // 取得当前点的颜色
                    int nOldX = 0, nOldY = 0;
                    nOldX = bXDir ? i + (int)(dy * dMultValue) : i;
                    nOldY = bXDir ? j : j + (int)(dy * dMultValue);

                    System.Drawing.Color color = srcBmp.GetPixel(i, j);
                    if (nOldX >= 0 && nOldX < destBmp.Width
                     && nOldY >= 0 && nOldY < destBmp.Height)
                    {
                        destBmp.SetPixel(nOldX, nOldY, color);
                    }
                }
            }

            return destBmp;
        }



        #endregion
    }
    #endregion
}
